open Fr
open FrGui

let canvas ?menu ?popup f =
	let widget = GMisc.drawing_area () in
	
	(* do actually we need to convert to user coords?
	 * it seems not, but not tested on high-dpi display
	 * (where Cairo makes 1 user = 2 device) *)
	(*let matrix = ref None in
	ignore (widget#event#connect#configure (fun _ ->
		matrix := Some (Cairo.Matrix.invert (Cairo.get_matrix (Cairo_lablgtk.create widget#misc#window))); false));
	ignore (widget#misc#connect#unrealize (fun () -> matrix := None));
	
	let p2c (x, y) =
		match !matrix with
		| Some m ->
			let p = Cairo.Matrix.transform_point m { Cairo.x = x; y = y } in
			p.Cairo.x, p.Cairo.y
		| None -> print_endline "oops"; assert false
	and d2c (x, y) =
		match !matrix with
		| Some m ->
			let p = Cairo.Matrix.transform_distance m { Cairo.x = x; y = y } in
			p.Cairo.x, p.Cairo.y
		| None -> print_endline "oops"; assert false in*)
		
	(* we need to not generate expose on resize *)
	let expose = lift_event true widget#event#connect#expose in
	register_e_with widget (lift begin
		let c = Cairo_lablgtk.create widget#misc#window in
		(try Cairo_lablgtk.region c (GdkEvent.Expose.region %expose)
		(* region not supported in GTK < 2.8 *)
		 with Failure _ ->
		 	Cairo_lablgtk.rectangle c (GdkEvent.Expose.area %expose));
		Cairo.clip c;
		@f c
	end);
	add_popup_menu ?menu ?popup widget;
	coerce_widget (new behavior_view_widget
		~expand: true
		widget
		(fun f ->
			(* hack to prevent GTK from reentering Fr *)
			ignore (GMain.Idle.add (fun () -> widget#misc#draw None; false)))
		f),
	lift_input ~p2c: id ~d2c: id widget#coerce widget#event
